package de.tudarmstadt.ukp.muip.fibqdojo.util;

import java.util.HashMap;
import java.util.List;

import de.tudarmstadt.ukp.muip.fibqdojo.interfaces.IFIBQFrequencyProvider;
import de.tudarmstadt.ukp.muip.fibqdojo.interfaces.IFIBQSentence;

/**
 * Takes sentences, splits them into ngrams of specified size and stores each
 * ngrams occurence in a frequency distribution
 * 
 * @author Tobias Horsmann
 */
public class NGramFrequencyProvider implements IFIBQFrequencyProvider {

    private final List<IFIBQSentence> sentencePool;
    private FrequencyDistribution frequencyDistribution;
    private final Integer[] ngrams;

    public NGramFrequencyProvider(List<IFIBQSentence> sentencePool, Integer[] ngrams) {
        validateNGrams(ngrams);
        this.sentencePool = sentencePool;
        this.ngrams = ngrams;
        frequencyDistribution = make3GramDistributionOfPartOfSpeech();
    }

    private void validateNGrams(Integer[] ngrams) {
        if (!allNgramValuesGreaterZero(ngrams)) {
            throw new IllegalArgumentException("A ngram has to be greater zero");
        }
        if (!noDoubleValues(ngrams)) {
            throw new IllegalArgumentException("The same ngram value were specified twice");
        }
    }

    private boolean noDoubleValues(Integer[] ngrams) {
        HashMap<Integer, String> map = new HashMap<Integer, String>();
        for (Integer ngram : ngrams) {
            if (!map.containsKey(ngram)) {
                map.put(ngram, "");
            } else {
                return false;
            }
        }

        return true;
    }

    private boolean allNgramValuesGreaterZero(Integer[] ngrams) {
        for (Integer ngram : ngrams) {
            if (ngram <= 0) {
                return false;
            }
        }
        return true;
    }

    private FrequencyDistribution make3GramDistributionOfPartOfSpeech() {
        String separator = " ";
        FrequencyDistribution freqDist = new FrequencyDistribution();
        for (int ngram : ngrams) {
            NGramConverter converter = new NGramConverter(ngram);
            for (IFIBQSentence sentence : sentencePool) {
                List<NGram> ngrams = converter.convert(sentence, separator);
                addNGramsToFreqDist(ngrams, freqDist);
            }
        }
        return freqDist;
    }

    private void addNGramsToFreqDist(List<NGram> ngrams, FrequencyDistribution freqDist) {
        for (NGram ngram : ngrams) {
            freqDist.put(ngram.getConcatNGram().toLowerCase());
        }
    }

    @Override
    public long getFrequency(String string) {
        return frequencyDistribution.getFrequency(string);
    }

}
